[设计模式]之一:简单工厂模式


设计模式系列目录

系列前言

最近思考了一下这两年的工作:做Android的时候一直看Android知识,做iOS的时候一直学iOS的东西。其实看起来感觉这样没什么问题,但仔细想想,我发现自己一直忽略了一大片知识点,那就是软件工程。不同的语言,不同的开发方向的确在代码上有千差万别,但是回到软件架构上来看,所有的编程思想都是相通的,比如说算法,再比如说设计模式。算法这点可能在移动开发中用得较少,但设计模式是必不可少的。我回想了一下,虽说写了不少代码,也考虑过一些关于模块代码结构的设计,但还是缺乏对这一块的系统了解。所以就找了一本众人推荐的书——《大话设计模式》来看。这本书写的的确好,通俗易懂,所以在这里我也推荐一下。这本书看了几个章节我就有一种受人点拨的感觉,明显感觉到如果我把这本书吃透,编码水平肯定能提高一个level。想到我的读书列表还有几本受到程序员追捧的大作要看,突然有种迫不及待就要一本一本读下去的感觉。不过读书可不是读一遍就完事的,关键就在于悟。进步也不能急,一点一点来吧。加油!


23种设计模式

关于设计模式最好的书应该是GoF的《设计模式》了,其中列出了23种设计模式,这里先列出来,后面写完对应博客会把这里改为文章链接方便查看。

  1. Singleton 单例模式
  2. Abstract Factory 抽象工厂模式
  3. Builder 生成器模式
  4. Factory Method 工厂方法模式
  5. Prototype 原型模式
  6. Adapter 适配器模式
  7. Bridge 桥接模式
  8. Composite 组合模式
  9. Decorator 装饰模式
  10. Facade 外观模式
  11. Flyweight 享元模式
  12. Proxy 代理模式
  13. Template Method模板方法
  14. Command 命令模式
  15. Interpreter 解释器模式
  16. Mediator 中介者模式
  17. Iterator 迭代器模式
  18. Observer 观察者模式
  19. Chain Of Responsibility 职责链模式
  20. Memento 备忘录模式
  21. State 状态模式
  22. Strategy 策略模式
  23. Visitor 访问者模式
  24. Design Principles 设计原则

实现四则运算

下面直接先上代码,因为一开始就说太多概念容易让人看不下去。
对于四则运算,也就是简单的加减乘除,实现起来并不难,但我们要用面向对象的角度去思考代码。加减乘除属于四种不同且独立的功能,所以应该分别地实现与封装,这样修改代码的时候也会方便一些,不会误改其他功能的代码。
另外,对于这四种运算都有一个相同点,那就是运算都需要两个数字来完成,考虑到这一点,就可以设计一个基类,在基类中定义两个用于计算的变量,再声明一个获取计算结果的方法。之后,四则运算分别继承这个基类,各自实现返回结果的方法。

///Operation.h
@interface Operation : NSObject

@property (nonatomic, assign) CGFloat number1;
@property (nonatomic, assign) CGFloat number2;

- (CGFloat)getResult;

@end
///Operation.m
@interface Operation : NSObject

@property (nonatomic, assign) CGFloat number1;
@property (nonatomic, assign) CGFloat number2;

- (CGFloat)getResult;

@end
///OpAdd.h
@interface OpAdd : Operation

@end
///OpAdd.m
@implementation OpAdd

- (CGFloat)getResult {
    return self.number1 + self.number2;
}

@end
///OpMns.m
@implementation OpMns

- (CGFloat)getResult {
    return self.number1 - self.number2;
}

@end
///OpMul.m
@implementation OpMul

- (CGFloat)getResult {
    return self.number1 * self.number2;
}

@end
///OpDiv.m
@implementation OpDiv

- (CGFloat)getResult {
    if (self.number2 == 0) {
        NSLog(@"除数不能为零");
        return 0;
    } else {
        return self.number1 / self.number2;
    }
}

@end

好了,功能封装完毕,下面就可以直接用这些写好的功能了,比如我要做加法

Operation *operation = [OpAdd new];
operation.number1 = 1;
operation.number2 = 2;
NSLog(@"operation result: %f", [operation getResult]);

但这样做的话我每次做运算时都需要知道我到底要实例化谁。为了方便起见,可以设计一个工厂类,专门用来做这个实例化的过程,这就是简单工厂模式。

typedef NS_ENUM(int, TYPE_OPERATION) {
    OPERATION_ADD = 0,
    OPERATION_MNS,
    OPERATION_MUL,
    OPERATION_DIV
};

@interface OperationSimpleFactory : NSObject

+ (Operation *)CreateOperationWithType:(enum TYPE_OPERATION)type;

@end

@implementation OperationSimpleFactory

+ (Operation *)CreateOperationWithType:(enum TYPE_OPERATION)type {

    Operation *op = nil;
    switch (type) {
        case OPERATION_ADD:
            op = [OpAdd new];
            break;
        case OPERATION_MNS:
            op = [OpMns new];
            break;
        case OPERATION_MUL:
            op = [OpMul new];
            break;
        case OPERATION_DIV:
            op = [OpDiv new];
            break;
        default:
            break;
    }
    return op;
}

@end

设计好工厂就可以直接使用工厂类实例化合适的对象,通过多态,返回父类的方式实现运算。

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        Operation *op = [OperationSimpleFactory CreateOperationWithType:OPERATION_ADD];
        op.number1 = 10;
        op.number2 = 20;
        NSLog(@"operation result: %f", [op getResult]);
    }
    return 0;
}

这里工厂类的CreateOperationWithType:方法是类方法,所以使用的时候不需要实例化工厂类,直接使用该方法传入参数就能够获得对应的运算实例。

但对于这段代码,如果我想要增加一个新的计算方法,比如用两个数字取log,这样我就需要首先创建一个计算log的功能类,然后修改工厂类的代码,增加一个switch分支。但是修改工厂类并不符合开放封闭原则,这里可以使用反射机制进行处理。

static NSString *kOperationAdd = @"OpAdd";
static NSString *kOperationMns = @"OpMns";
static NSString *kOperationMul = @"OpMul";
static NSString *kOperationDiv = @"OpDiv";

@interface OperationSimpleFactory : NSObject

+ (Operation *)CreateOperationWithType:(NSString *)type;

@end

@implementation OperationSimpleFactory

+ (Operation *)CreateOperationWithType:(NSString *)type {
      return [NSClassFromString(type) new]; 
}

@end

这里定义几个字符串常量,字符串内容和功能类名保持一致,将字符串作为参数即可。

简单工厂模式

简单工厂模式中定义一个抽象类,抽象类中声明公共的特征及属性,抽象子类继承自抽象类,去实现具体的操作。工厂类根据外界需求,在工厂类中创建对应的抽象子类实例并传给外界,而对象的创建是由外界决定的。外界只需要知道抽象子类对应的参数即可,而不需要知道抽象子类的创建过程,在外界使用时甚至不用引入抽象子类。

简单工厂模式将操作对象的创建,和关于操作对象相关的业务逻辑分离开,降低操作对象的耦合度。由于工厂类只是为外界创建对象,所以并不需要实例化工厂类对象,只需要为外界提供类方法即可。外界需要什么类型的抽象子类,只需要传递对应的参数即可。

UML类图

UML

小结

在简单工厂模式中,一个工厂类负责所有产品对象的创建,这个工厂类的职责大大增加,可能客户端对于某些产品的创建方式会有不同的要求,这样的话,就要不断的修改工厂类,增加相应的逻辑,不利于后期的代码维护。
另外,由于简单工厂模式使用静态方法创建,这就导致静态方法无法被继承。
所以,简单工厂模式适用于创建的对象比较少或简单的情况。

Swift代码

因为最近也在看Swift,所以会用Swift做一些练习练习

class Operation {
    var number1: CGFloat = 0.0
    var number2: CGFloat = 0.0

    func getResult() -> CGFloat {
        return 0
    }
}

class OpAdd: Operation {
    override func getResult() -> CGFloat {
        return self.number1 + self.number2
    }
}

class OpMns: Operation {
    override func getResult() -> CGFloat {
        return self.number1 - self.number2
    }
}

class OpMul: Operation {
    override func getResult() -> CGFloat {
        return self.number1 * self.number2
    }
}

class OpDiv: Operation {
    override func getResult() -> CGFloat {
        if self.number2 == 0 {
            print("除数不得为零")
            return 0
        } else {
            return self.number1 / self.number2
        }
    }
}

enum OperationType {
    case OperationAdd
    case OperationMns
    case OperationMul
    case OperationDiv
}

class OperationSimpleFactory {
    static func CreateOperationWithType(type: OperationType) -> Operation {
        var operation: Operation
        switch type {
        case .OperationAdd:
            operation = OpAdd()
        case .OperationMns:
            operation = OpMns()
        case .OperationMul:
            operation = OpMul()
        case .OperationDiv:
            operation = OpDiv()
        }

        return operation
    }
}



let op: Operation = OperationSimpleFactory.CreateOperationWithType(OperationType.OperationAdd)
op.number1 = 10
op.number2 = 20
print("result by Add is", op.getResult())

文章作者: Wossoneri
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC 4.0 许可协议。转载请注明来源 Wossoneri !
评论
  目录